IOMMU: add crash_shutdown iommu_op
authorAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 15 Jun 2011 15:10:11 +0000 (16:10 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 15 Jun 2011 15:10:11 +0000 (16:10 +0100)
The kdump kernel has problems booting with interrupt/dma
remapping enabled, so we need a new iommu_ops called
crash_shutdown which is basically suspend but doesn't
need to bother saving state.

Make sure that crash_shutdown is called on the kexec
path.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
xen/arch/x86/crash.c
xen/drivers/passthrough/amd/pci_amd_iommu.c
xen/drivers/passthrough/iommu.c
xen/drivers/passthrough/vtd/iommu.c
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
xen/include/xen/iommu.h

index 1fa7ef7db6afd45acf911e4d49dd827439300fb7..19508550df285dba8a19a5bf5df07fdd0ba4fbda 100644 (file)
@@ -77,6 +77,10 @@ static void nmi_shootdown_cpus(void)
         msecs--;
     }
 
+    /* Crash shutdown any IOMMU functionality as the crashdump kernel is not
+     * happy when booting if interrupt/dma remapping is still enabled */
+    iommu_crash_shutdown();
+
     __stop_this_cpu();
     disable_IO_APIC();
 }
index 10b6db36b99dc8b28ede8da5bdce939b9bb91179..fae9ae44ff3d9fa948030382fe928f57a645c154 100644 (file)
@@ -456,4 +456,5 @@ const struct iommu_ops amd_iommu_ops = {
     .suspend = amd_iommu_suspend,
     .resume = amd_iommu_resume,
     .share_p2m = amd_iommu_share_p2m,
+    .crash_shutdown = amd_iommu_suspend,
 };
index 0a9965d4082007c39a4abd81bb7f1bd95e3a5ef5..cd8d10a363fcb7453f609c1d9668433eea6aea3f 100644 (file)
@@ -432,6 +432,14 @@ void iommu_share_p2m_table(struct domain* d)
         ops->share_p2m(d);
 }
 
+void iommu_crash_shutdown(void)
+{
+    const struct iommu_ops *ops = iommu_get_ops();
+    if ( iommu_enabled )
+        ops->crash_shutdown();
+    iommu_enabled = 0;
+}
+
 /*
  * Local variables:
  * mode: C
index 79ab4c20421a6aa170b157978ad254db4d067d8d..a8d806ba781d275a314ccd5ace6f5f29e096c302 100644 (file)
@@ -2235,6 +2235,25 @@ static void vtd_suspend(void)
     }
 }
 
+static void vtd_crash_shutdown(void)
+{
+    struct acpi_drhd_unit *drhd;
+    struct iommu *iommu;
+
+    if ( !iommu_enabled )
+        return;
+
+    iommu_flush_all();
+
+    for_each_drhd_unit ( drhd )
+    {
+        iommu = drhd->iommu;
+        iommu_disable_translation(iommu);
+        disable_intremap(drhd->iommu);
+        disable_qinval(drhd->iommu);
+    }
+}
+
 static void vtd_resume(void)
 {
     struct acpi_drhd_unit *drhd;
@@ -2286,6 +2305,7 @@ const struct iommu_ops intel_iommu_ops = {
     .suspend = vtd_suspend,
     .resume = vtd_resume,
     .share_p2m = iommu_set_pgd,
+    .crash_shutdown = vtd_crash_shutdown,
 };
 
 /*
index c1c23333b202a24c7d9c7d7de4e0f6fe6d89ce62..10d6cc93d4bb4c50e8637c9e10e816e75858a670 100644 (file)
@@ -102,6 +102,7 @@ extern void *shared_intremap_table;
 /* power management support */
 void amd_iommu_resume(void);
 void amd_iommu_suspend(void);
+void amd_iommu_crash_shutdown(void);
 
 static inline u32 get_field_from_reg_u32(u32 reg_value, u32 mask, u32 shift)
 {
index 2dee3f2982437e7d4d64c2e4fa0dab3fc114c11c..31476c20c1f1c3dcb6f14a12aa6f0783e84a2f44 100644 (file)
@@ -133,6 +133,7 @@ struct iommu_ops {
     void (*suspend)(void);
     void (*resume)(void);
     void (*share_p2m)(struct domain *d);
+    void (*crash_shutdown)(void);
 };
 
 void iommu_update_ire_from_apic(unsigned int apic, unsigned int reg, unsigned int value);
@@ -142,6 +143,7 @@ unsigned int iommu_read_apic_from_ire(unsigned int apic, unsigned int reg);
 
 void iommu_suspend(void);
 void iommu_resume(void);
+void iommu_crash_shutdown(void);
 
 void iommu_set_dom0_mapping(struct domain *d);
 void iommu_share_p2m_table(struct domain *d);